home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-05 / drivers1.zip / LOCALTLK.ASM < prev    next >
Assembly Source File  |  1992-01-23  |  36KB  |  1,323 lines

  1. version    equ    3
  2.  
  3.     include    defs.asm
  4.  
  5. ; PC/FTP Packet Driver source, conforming to version 1.09 of the spec
  6. ; Katie Stevens (dkstevens@ucdavis.edu)
  7. ; Computing Services, University of California, Davis
  8. ; Portions (C) Copyright 1988 Regents of the University of California
  9.  
  10. ; This program is free software; you can redistribute it and/or modify
  11. ; it under the terms of the GNU General Public License as published by
  12. ; the Free Software Foundation, version 1.
  13. ;
  14. ; This program is distributed in the hope that it will be useful,
  15. ; but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ; GNU General Public License for more details.
  18.  
  19. ; Change History
  20. ;
  21. ; 05-90        ks    Katie Stevens (dkstevens@ucdavis.edu):
  22. ;            - Created
  23. ; 07-19-91    jgn    Jim Noble (noble_jim@po.gis.prc.com):
  24. ;            - Added Change History and documented changes
  25. ;            - Fixed a bug that caused AppleTalk network numbers to
  26. ;              be byte-swapped when printed
  27. ;            - Fixed a bug that caused the wrong buffer address to 
  28. ;              be passed to the packet receiver upcall routine
  29. ;            - Made changes in the driver information structure to 
  30. ;              match LocalTalk:  size of MAC-layer address, MTU,
  31. ;              and multicast buffer size
  32. ;            - Changed the packet buffer sizes from 1024 to 586,
  33. ;              the maximum amount of data in a DDP packet
  34. ;            - Commented-out the noop_upcall completion routine and
  35. ;              changed the completion routine address passed to
  36. ;              the AppleTalk driver to 0000:0000 for all driver
  37. ;              calls
  38. ;            - Set the status field to -1 prior to the GetNetInfo
  39. ;              AppleTalk driver call as per the recommendation of
  40. ;              the driver interface spec.
  41. ;            - Added structure definitions for short and long 
  42. ;              format DDP packets and used them when adding a
  43. ;              check to ensure that received packets are IP packets
  44. ; 07-22-91    jgn    Jim Noble (noble_jim@po.gis.prc.com):
  45. ;            - Fixed a bug that would prevent the packet driver
  46. ;              from initializing with a static address if there
  47. ;              were no dynamic addresses available
  48. ; 07-23-91    jgn    Jim Noble (noble_jim@po.gis.prc.com):
  49. ;            - Added the optional IP address to the usage message
  50. ;            - Incremented version to 3
  51. ;
  52.  
  53. code    segment    word public
  54.     assume    cs:code, ds:code
  55.  
  56. ; Definitions specific to the ATALK.SYS driver for PC LocalTalk cards:
  57. ; these include Apple LocalTalk PC Card, Sun/TOPS FlashCard
  58. ; For a complete description of the LocalTalk commands, structures and
  59. ; methods used in this driver, please refer to Apple APDA document #M7055,
  60. ; LocalTalk PC Card and Driver Preliminary Notes.
  61.  
  62. driverstring    db    'AppleTalk', 0        ; ATALK.SYS signature string
  63. dot_char    db    '.', 0            ; for IP address display
  64.  
  65. AT_INT        equ    5CH            ; Software int# for ATALK.SYS
  66.  
  67. ; General ATALK.SYS driver commands
  68. AT_INIT            equ    01H        ; Initialize driver software
  69. AT_GETNETINFO        equ    03H        ; Get driver info
  70.  
  71. ; Datagram Delivery Protocol commands for ATALK.SYS driver
  72. DDP_OPENSOCKET        equ    20H
  73. DDP_CLOSESOCKET        equ    21H
  74. DDP_WRITE        equ    22H
  75. DDP_READ        equ    23H
  76. DDP_CANCEL        equ    24H
  77.  
  78. ; Name Binding Protocol commands for ATALK.SYS driver
  79. NBP_REGISTER        equ    30H
  80. NBP_REMOVE        equ    31H
  81. NBP_LOOKUP        equ    32H
  82. NBP_CONFIRM        equ    33H
  83. NBP_CANCEL        equ    34H
  84.  
  85. ; AppleTalk Transaction Protocol commands for ATALK.SYS driver
  86. ATP_SEND_REQUEST    equ    42H
  87.  
  88. ; ATALK.SYS command qualifiers
  89. ASYNC_MASK    equ    8000H        ; Start command, then return
  90. INTR_MASK    equ    4000H        ; Wait for intr service to complete
  91.  
  92. XO_BIT        equ    20H        ; ATP - exactly once transaction
  93.  
  94. ; Structure for short format DDP packet [jgn]
  95. DDPshort struc
  96.     lap_dst        db    ?    ; destination node
  97.     lap_src        db    ?    ; source node
  98.     lap_type    db    ?    ; 1 for short format DDP packet
  99.     ddps_len    dw    ?    ; packet length
  100.     ddps_dskt    db    ?    ; destination socket
  101.     ddps_sskt    db    ?    ; source socket
  102.     ddps_type    db    ?    ; 22 for IP packets
  103. DDPshort ends
  104.  
  105. ; Structure for long format DDP packet [jgn]
  106. DDPlong struc
  107.     lap_dst        db    ?    ; destination node
  108.     lap_src        db    ?    ; source node
  109.     lap_type    db    ?    ; 2 for long format DDP packets
  110.     ddpl_len    dw    ?    ; packet length
  111.     ddpl_chksum    dw    ?    ; checksum
  112.     ddpl_dnet    dw    ?    ; destination network
  113.     ddpl_snet    dw    ?    ; source network
  114.     ddpl_dnode    db    ?    ; destination node
  115.     ddpl_snode    db    ?    ; source node
  116.     ddpl_dskt    db    ?    ; destination socket
  117.     ddpl_sskt    db    ?    ; source socket
  118.     ddpl_type    db    ?    ; 22 for IP packets
  119. DDPlong ends
  120.  
  121. ; Structure for AppleTalk node addressing
  122. AddrBlk struc
  123.     ablk_network    dw    0
  124.     ablk_nodeid    db    0
  125.     ablk_socket    db    0
  126. AddrBlk ends
  127.  
  128. ; Structure for general calls to AppleTalk driver (ATALK.SYS)
  129. InfoParams struc
  130.     atd_command    dw        AT_GETNETINFO
  131.     atd_status    dw        0
  132.     atd_compfun    segmoffs    <>
  133.     inf_network    dw        0
  134.     inf_nodeid    db        0
  135.     inf_abridge    db        0
  136.     inf_config    dw        0
  137.     inf_buffptr    segmoffs    <>
  138.     inf_buffsize    dw        0
  139. InfoParams ends
  140. ; Parameter block for general calls to AppleTalk driver (ATALK.SYS)
  141. MyInfo    InfoParams    <>
  142.  
  143. ; Address block for our gateway
  144. MyGateway    AddrBlk        <>
  145.  
  146. ; Structure for calls to AppleTalk driver (ATALK.SYS) for Datagram
  147. ; Delivery Protocol (DDP) service
  148. DDPParams struc
  149.     ddp_command    dw        0
  150.     ddp_status    dw        0
  151.     ddp_compfun    segmoffs    <>
  152.     ddp_addr    AddrBlk        <>
  153.     ddp_socket    db        0
  154.     ddp_type    db        0
  155.     ddp_buffptr    segmoffs    <>
  156.     ddp_buffsize    dw        0
  157.     ddp_chksum    db        0
  158. DDPParams ends
  159. ; Parameter blocks for AppleTalk DDP access
  160. DDPio        DDPParams    <>        ; Write on DDP socket
  161. ; 2 buffers for packet receive from ATALK.SYS
  162. DDP1inuse    db    0            ; Buffer occupied flag
  163. DDP1buffsize    dw    0            ; Buffer length during reads
  164. DDP1buffer    db    586 dup (0)        ; Buffer for DDP read [jgn]
  165. DDP2inuse    db    0            ; 2nd Buffer occupied flag
  166. DDP2buffsize    dw    0            ; 2nd Buffer length during reads
  167. DDP2buffer    db    586 dup (0)        ; 2nd Buffer for DDP read [jgn]
  168.  
  169. ; Structure for calls to AppleTalk driver (ATALK.SYS) for Name
  170. ; Binding Protocol (NBP) service
  171. NBPParams struc
  172.     nbp_command    dw        0
  173.     nbp_status    dw        0
  174.     nbp_compfun    segmoffs    <>
  175.     nbp_addr    AddrBlk        <>
  176.     nbp_toget    dw        0
  177.     nbp_buffptr    segmoffs    <>
  178.     nbp_buffsize    dw        0
  179.     nbp_interval    db        0
  180.     nbp_retry    db        0
  181.     nbp_entptr    segmoffs    <>
  182. NBPParams ends
  183. ; Parameter block for AppleTalk NBP access
  184. NBP        NBPParams    <>
  185.  
  186. ; Structure for name-to-address bind entries
  187. NBPTuple struc
  188.     tup_address    AddrBlk        <>
  189.     tup_enum    db        0
  190.     tup_name    db        99 dup(0)
  191. NBPTuple ends
  192. ; Name Binding Tuple for our IP gateway
  193. NBPt        NBPTuple    <>
  194.  
  195. ; Structure for name-to-address table
  196. NBPEntry struc
  197.     tab_next    segmoffs    <>
  198.     tab_entry    NBPTuple    <>
  199. NBPEntry ends
  200. NBPtable    NBPEntry    <>
  201.  
  202. ; Structure for calls to AppleTalk driver (ATALK.SYS) for AppleTalk
  203. ; Transaction Protocol (ATP) service
  204. ATPParams struc
  205.     atp_command    dw        0
  206.     atp_status    dw        0
  207.     atp_compfun    segmoffs    <>
  208.     atp_addrblk    AddrBlk        <>
  209.     atp_socket    db        0
  210.     atp_fill    db        0
  211.     atp_buffptr    segmoffs    <>
  212.     atp_buffsize    dw        0
  213.     atp_interval    db        0
  214.     atp_retry    db        0
  215.     atp_flags    db        0
  216.     atp_seqbit    db        0
  217.     atp_tranid    dw        0
  218.     atp_userbytes    db        4 dup(0)
  219.     atp_bdsbuffs    db        0
  220.     atp_bdsresps    db        0
  221.     atp_bdsptr    segmoffs    <>
  222. ATPParams ends
  223. ; Parameter block for AppleTalk ATP access
  224. ATP        ATPParams    <>
  225.  
  226. ; Structure for BDS elements
  227. BDSElement struc
  228.     bds_buffptr    segmoffs    <>
  229.     bds_buffsize    dw        0
  230.     bds_datasize    dw        0
  231.     bds_userbytes    db        4 dup(0)
  232. BDSElement ends
  233. ; Parameter block for our BDS element
  234. BDS        BDSElement    <>
  235.  
  236. ; Struct for IP gateway information
  237. IPGInfo struc
  238.     ipg_opcode    db        0,0,0,1    ; IPGP_ASSIGN
  239.     ipg_ipaddress    dd        0    ; our IP address
  240.     ipg_ipname    dd        0    ; nameserver IP address
  241.     ipg_ipbroad    dd        0    ; broadcast IP address
  242.     ipg_ipfile    dd        0    ; file server IP address
  243.     ipg_ipother    dd        4 dup (0)
  244.     ipg_string    db        128 dup (0), '$'
  245. IPGInfo ends
  246. ; Parameter block for info about our IP gateway
  247. IPG        IPGInfo        <>
  248.  
  249. IPG_ERROR    equ    -1
  250.  
  251. static_address    db    0, 0, 0, 0
  252. use_static    db    0
  253. test_address    db    0, 0, 0, 0
  254. temp_4bytes    db    0, 0, 0, 0
  255.  
  256. ; End of Appletalk parameter definitions
  257.  
  258. ; The following values may be overridden from the command line.
  259. ; If they are omitted from the command line, these defaults are used.
  260.  
  261.     public    int_no
  262. int_no    db    0,0,0,0            ;must be four bytes long for get_number.
  263.  
  264.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  265. driver_class    db    5,0        ;from the packet spec
  266. driver_type    db    1        ;from the packet spec
  267. driver_name    db    'LocalTalk',0    ;name of the driver.
  268. driver_function    db    2
  269. parameter_list    label    byte
  270.     db    1    ;major rev of packet driver
  271.     db    9    ;minor rev of packet driver
  272.     db    14    ;length of parameter list
  273.     db    4    ;length of MAC-layer address [jgn]
  274.     dw    586    ;MTU, including MAC headers [jgn]
  275.     dw    0    ;buffer size of multicast addrs [jgn]
  276.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  277.     dw    0    ;(# of successive xmits) - 1
  278. int_num    dw    0    ;Interrupt # to hook for post-EOI
  279.             ;processing, 0 == none,
  280.  
  281.     public    rcv_modes
  282. rcv_modes    dw    4        ;number of receive modes in our table.
  283.         dw    0,0,0,rcv_mode_3
  284.  
  285.     public    as_send_pkt
  286. ; The Asynchronous Transmit Packet routine.
  287. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  288. ;   interrupts possibly enabled.
  289. ; Exit with nc if ok, or else cy if error, dh set to error number.
  290. ;   es:di and interrupt enable flag preserved on exit.
  291. as_send_pkt:
  292.     ret
  293.  
  294.     public    drop_pkt
  295. ; Drop a packet from the queue.
  296. ; Enter with es:di -> iocb.
  297. drop_pkt:
  298.     assume    ds:nothing
  299.     ret
  300.  
  301.     public    xmit
  302. ; Process a transmit interrupt with the least possible latency to achieve
  303. ;   back-to-back packet transmissions.
  304. ; May only use ax and dx.
  305. xmit:
  306.     assume    ds:nothing
  307.     ret
  308.  
  309.     public    send_pkt
  310. send_pkt:
  311. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  312. ;  (only if the high-performance bit is set in driver_function)
  313. ;enter with ds:si -> packet, cx = packet length.
  314. ;if we're a high-performance driver, es:di -> upcall.
  315. ;exit with nc if ok, or else cy if error, dh set to error number.
  316.     assume    ds:nothing
  317. ; send packet to AppleTalk/DDP/IP gateway
  318.     ; load info about the packet we are sending
  319.     mov    DDPio.ddp_buffptr.offs, si
  320.     mov    DDPio.ddp_buffptr.segm, ds    ; DDPio.buffptr -> IP packet
  321.     mov    DDPio.ddp_buffsize, cx        ; DDPio.buffsize = packet len
  322.  
  323.     ; send all packets to the IP gateway
  324.     mov    cx, (size AddrBlk)        ; DDPio.ddp_addr = MyGateway
  325.     mov    ax, cs
  326.     mov    ds, ax
  327.     mov    es, ax
  328.     mov    si, offset MyGateway
  329.     mov    di, offset DDPio.ddp_addr
  330.     rep    movsb
  331.  
  332.     mov    bx, offset DDPio
  333.     call    doATint                ; Ask ATALK.SYS to send packet
  334.  
  335.     cmp    DDPio.ddp_status, 00H        ; Packet sent okay?
  336.     je    send_ret            ; Yes, status is good
  337.                         ; No, status gives error
  338. send_err:
  339.     call    count_out_err
  340.     mov    dh, CANT_SEND            ; set error flag
  341.     stc
  342.     ret
  343.  
  344. send_ret:
  345.     clc                    ; packet sent successfully
  346.     ret
  347.  
  348.     public    get_address
  349. get_address:
  350. ;get the address of the interface.
  351. ;enter with es:di -> place to get the address, cx = size of address buffer.
  352. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  353.     assume    ds:code
  354.     ret
  355.  
  356.  
  357.     public    set_address
  358. set_address:
  359. ;enter with ds:si -> Ethernet address, CX = length of address.
  360. ;exit with nc if okay, or cy, dh=error if any errors.
  361.     assume    ds:nothing
  362.     mov    dh, BAD_COMMAND
  363.     stc
  364.     ret
  365.  
  366.  
  367. rcv_mode_3:
  368. ;receive mode 3 is the only one we support, so we don't have to do anything.
  369.     ret
  370.  
  371.  
  372.     public    set_multicast_list
  373. set_multicast_list:
  374. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  375. ;return nc if we set all of them, or cy,dh=error if we didn't.
  376.     mov    dh,NO_MULTICAST
  377.     stc
  378.     ret
  379.  
  380.  
  381.     public    terminate
  382. terminate:
  383.     push    ds
  384.     push    cs
  385.     pop    ds
  386.  
  387. terminate_write:
  388.     ; close the DDP socket
  389.     mov    DDPio.ddp_command, DDP_CLOSESOCKET
  390.     mov    bx, offset DDPio
  391.     call    doATint
  392.  
  393.     mov    NBP.nbp_command, NBP_REMOVE
  394.     mov    NBP.nbp_entptr.offs, offset NBPtable.tab_entry.tup_name
  395.     mov    NBP.nbp_entptr.segm, ds
  396.     mov    bx, offset NBP
  397.     call    doATint
  398.  
  399.     pop    ds
  400.     ret
  401.  
  402.     public    reset_interface
  403. reset_interface:
  404. ;reset the interface.
  405.     assume    ds:code
  406.     ret
  407.  
  408.  
  409. ;called when we want to determine what to do with a received packet.
  410. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  411.     extrn    recv_find: near
  412.  
  413. ;called after we have copied the packet into the buffer.
  414. ;enter with ds:si ->the packet, cx = length of the packet.
  415.     extrn    recv_copy: near
  416.  
  417.     extrn    count_in_err: near
  418.     extrn    count_out_err: near
  419.  
  420.     public    recv
  421. recv:
  422. ;called from the recv isr.  All registers have been saved, and ds=cs.
  423. ;Upon exit, the interrupt will be acknowledged.
  424. ;NOTE: this packet driver merely makes calls to another hardware
  425. ;driver, ATALK.SYS. ATALK.SYS handles the hardware interrupt service;
  426. ;ATALK.SYS then calls this packet driver with FAR subroutine calls.
  427. ;the ATALK.SYS FAR subroutine is recv_at_upcall
  428.     assume    ds:nothing
  429.     ret
  430.  
  431.     public    recv_exiting
  432. recv_exiting:
  433. ;called from the recv isr after interrupts have been acknowledged.
  434. ;Only ds and ax have been saved.
  435.     assume    ds:nothing
  436.     ret
  437.  
  438. ;*******************************************
  439.  
  440. ; [jgn] Null completion routine is not needed.  Just specify 0000:0000 as the
  441. ; address of the completion routine for no call.
  442. ;
  443. ; NULL completion routine for ATALK.SYS drivers calls
  444. ;noop_upcall proc far
  445. ;    ret
  446. ;noop_upcall endp
  447.  
  448. ;First half routine for DDP socket.
  449. ;ATALK.SYS calls this routine when a packet is received.
  450. ;ATALK.SYS assumes we are a far procedure.
  451. ;    AH = socket
  452. ;    CX = size of data packet
  453. ;    DS:BX = address of buffer
  454. preview_upcall proc far
  455.     assume    ds:nothing
  456.  
  457. ;    maximum packet we can receive is 586 bytes [jgn]
  458.     cmp    cx, 586                ; Max size of DDP data field [jgn]
  459.     ja    preview_drop
  460.  
  461. ;    Is it an IP packet?  DDP type should be 22 [jgn]
  462.     cmp    byte ptr ds:[bx].lap_type, 1    ; Is it a short DDP packet?
  463.     jne    ddp_long            ; No, must be long DDP
  464.     cmp    byte ptr ds:[bx].ddps_type, 22    ; Is it an IP packet?
  465.     jne    preview_drop            ; No, refuse packet
  466.     jmp    preview_buff1
  467. ddp_long:
  468.     cmp    byte ptr ds:[bx].ddpl_type, 22    ; Is it an IP packet?
  469.     jne    preview_drop            ; No, refuse packet
  470.  
  471. preview_buff1:
  472.     cmp    DDP1inuse, 00H
  473.     jne    preview_buff2
  474.     mov    DDP1inuse, 01H
  475.  
  476. ;    repeat buffer size back to ATALK.SYS in CX
  477. ;    ask ATALK.SYS driver to pass us the buffer at DS:BX
  478. ;    tell ATALK.SYS address of 2nd half routine in ES:DX
  479.     push    cs
  480.     pop    ds
  481.     mov    bx, offset DDP1buffer        ; ds:bx->buffer
  482.     push    cs
  483.     pop    es
  484.     mov    dx, offset recv_at_upcall    ; es:dx->2nd half routine
  485.     jmp    preview_ret
  486.  
  487. preview_buff2:
  488.     cmp    DDP2inuse, 00H
  489.     jne    preview_drop
  490.     mov    DDP2inuse, 01H
  491.  
  492. ;    repeat buffer size back to ATALK.SYS in CX
  493. ;    ask ATALK.SYS driver to pass us the buffer at DS:BX
  494. ;    tell ATALK.SYS address of 2nd half routine in ES:DX
  495.     push    cs
  496.     pop    ds
  497.     mov    bx, offset DDP2buffer        ; ds:bx->buffer
  498.     push    cs
  499.     pop    es
  500.     mov    dx, offset recv_at_upcall    ; es:dx->2nd half routine
  501.     jmp    preview_ret
  502.  
  503.  
  504. preview_drop:
  505. ;    ask ATALK.SYS to drop the packet
  506.     call    count_in_err
  507.     mov    cx, 00h
  508.  
  509. preview_ret:
  510.     ret
  511. preview_upcall endp
  512.  
  513. ;Second half routine for DDP socket.
  514. ;ATALK.SYS calls this routine when the packet has been copied to our buffer.
  515. ;ATALK.SYS assumes we are a far procedure.
  516. ;    CX = size of data packet
  517. ;    DS:BX = address of buffer
  518. recv_at_upcall proc far
  519.     assume    ds:nothing
  520.  
  521. recv_buff1:
  522.     cmp    bx, offset DDP1buffer
  523.     jne    recv_buff2
  524.  
  525. ;    check if we have a client waiting for packets
  526. ;    pass to recv_find    es:di->driver_type, cx=#bytes in packet
  527.     mov    DDP1buffsize, cx
  528.     mov    di, offset driver_type
  529.     push    cs
  530.     pop    es
  531.     mov    dl,cs:driver_class
  532.     call    recv_find
  533.  
  534. ;    es:di->client buffer, or es:di=0 means drop the packet
  535.     mov    ax, es
  536.     or    ax, di
  537.     je    recv_pass1
  538.  
  539. ;    copy ds:si->es:di for cx bytes
  540.     push    es                ; save the client buffer
  541.     push    di                ; address (es:di) [jgn]
  542.     push    cs
  543.     pop    ds
  544.     mov    si, offset DDP1buffer
  545.     mov    cx, DDP1buffsize
  546.     rep    movsb
  547.  
  548. ;    tell receiver copy has been made; ds:si->the packet, cx=length
  549.     pop    si                ; restore the client buffer
  550.     pop    ds                ; address into ds:si [jgn]
  551.     mov    cx, DDP1buffsize
  552.     call    recv_copy
  553.  
  554. recv_pass1:
  555. ;    first buffer is free for use again
  556.     mov    DDP1inuse, 00H
  557.     jmp    recv_ret
  558.  
  559.  
  560. recv_buff2:
  561.     cmp    bx, offset DDP2buffer
  562.     jne    recv_ret
  563.  
  564. ;    check if we have a client waiting for packets
  565. ;    pass to recv_find    es:di->driver_type, cx=#bytes in packet
  566.     mov    DDP2buffsize, cx
  567.     mov    di, offset driver_type
  568.     push    cs
  569.     pop    es
  570.     call    recv_find
  571.  
  572. ;    es:di->client buffer, or es:di=0 means drop the packet
  573.     mov    ax, es
  574.     or    ax, di
  575.     je    recv_pass2
  576.  
  577. ;    copy ds:si->es:di for cx bytes
  578.     push    es                ; save the client buffer
  579.     push    di                ; address (es:di) [jgn]
  580.     push    cs
  581.     pop    ds
  582.     mov    si, offset DDP2buffer
  583.     mov    cx, DDP2buffsize
  584.     rep    movsb
  585.  
  586. ;    tell receiver copy has been made; ds:si->the packet, cx=length
  587. ;    push    es
  588.     pop    si                ; restore the client buffer
  589.     pop    ds                ; address into ds:si [jgn]
  590. ;    mov    si, offset DDP2buffer
  591.     mov    cx, DDP2buffsize
  592.     call    recv_copy
  593. recv_pass2:
  594. ;    second buffer is now free for use
  595.     mov    DDP2inuse, 00H
  596.  
  597. recv_ret:
  598.     ret
  599. recv_at_upcall endp
  600.  
  601. ;*******************************************
  602.  
  603. ; Call DOS software interrupt for AppleTalk
  604. ; caller must set ds:bx -> parameter block for ATALK.SYS
  605. doATint:
  606.     int    AT_INT                ; Interrupt ATALK.SYS driver
  607.     ret
  608.  
  609.  
  610.  
  611. ;any code after this will not be kept after initialization.
  612. end_resident    label    byte
  613. ;****************************************************************************
  614.  
  615.     public    usage_msg
  616. usage_msg    db    "usage: localtlk [-n] [-d] [-w] <packet_int_no> [ <IP address> ]",CR,LF,'$' ; [jgn]
  617.  
  618.     public    copyright_msg
  619. copyright_msg    db    "Packet driver for Apple LocalTalk PC Card, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
  620.         db    "Portions Copyright 1990, Regents of the University of California",CR,LF,'$'
  621.  
  622. no_atalk_sys_msg:
  623.     db    "Couldn't locate ATALK.SYS -- packet driver not installed",CR,LF,'$'
  624. atalk_sys_found_msg:
  625.     db    "ATALK.SYS driver located at software interrupt ",'$'
  626. inf_nodeid_name:
  627.     db    "Attaching to AppleTalk network as node ",'$'
  628. inf_abridge_name:
  629.     db    "AppleTalk network bridge is node ",'$'
  630. ddp_failed_msg:
  631.     db    "Datagram Delivery Protocol socket open failed; return status: ",'$'
  632. ddp_wrong_socket_msg:
  633.     db    "Datagram Delivery Protocol failed; unable to aquire requested socket",CR,LF,'$'
  634. ddp_open_msg:
  635.     db    "Datagram Delivery Protocol open on socket ",'$'
  636. atalk_open_msg:
  637.     db    "Attached to AppleTalk network as (net:node:sock): ",'$'
  638. nbp_no_gateway_msg:
  639.     db    "NBP: IPGATEWAY lookup failed; return status: ",'$'
  640. nbp_ipg_addr_msg:
  641.     db    "IPGATEWAY located on AppleTalk network as (net:node:sock): ",'$'
  642. atp_no_gateway_msg:
  643.     db    "ATP: IPGATEWAY transport setup failed; return status: ",'$'
  644. ipg_gateway_err_msg:
  645.     db    "IP Gateway error: ",'$'
  646. myip_addr_msg:
  647.     db    "My IP address: ",'$'
  648. ns_ip_addr_msg:
  649.     db    "Name Server IP address: ",'$'
  650. bd_ip_addr_msg:
  651.     db    "Broadcast IP address: ",'$'
  652. fs_ip_addr_msg:
  653.     db    "File Server IP address: ",'$'
  654. opcode_msg:
  655.     db    "IPG opcode: ",'$'
  656. nbp_no_register_msg:
  657.     db    "NBP: failed, couldn't register our name; return status: ",'$'
  658. ddp_cant_recv:
  659.     db    "DDP: couldn't initiate read on socket; return status: ",'$'
  660. test_arg_msg:
  661.     db    "Test IP arg parsing: ",'$'
  662.  
  663.  
  664. ipgateway_name:
  665.     db    01H, '=', 09H, "IPGATEWAY", 01H, '*', '0'
  666. myip_name:
  667.     db    09H, "IPADDRESS", 01H, '*', '0'
  668. myip_name_len    equ    12
  669.  
  670. ; Temporary storage for calls to print_number
  671. dtemp    dw    ?
  672.     dw    0
  673.  
  674.  
  675.     extrn    set_recv_isr: near
  676.  
  677. ;enter with si -> argument string, di -> wword to store.
  678. ;if there is no number, don't change the number.
  679.     extrn    get_number: near
  680.  
  681. ;enter with ds:dx -> argument string, ds:di -> dword to print.
  682.     extrn    print_number: near
  683.  
  684. ;enter with al = char to display
  685.     extrn    chrout: near
  686. ;enter with ax,dx holding 32 bits to display in decimal (ax holds low word)
  687.     extrn    decout: near
  688.     extrn    byteout: near
  689.     extrn    wordout: near
  690.  
  691.     extrn    skip_blanks: near
  692.  
  693. ;enter with si -> argument string, di -> word to store.
  694. ;if there is no number, don't change the number.
  695.     extrn    get_number: near
  696.  
  697. ;called with ds:si -> immediately after the packet_int_no
  698.     public    parse_args
  699. parse_args:
  700.     call    skip_blanks
  701.     lodsb
  702.     cmp    al, CR
  703.     je    no_more_args
  704.     cmp    al, '['                ; check for square brackets
  705.     je    past_brackets
  706.     dec    si                ; not a bracket, back up
  707. past_brackets:
  708.     mov    di, offset temp_4bytes        ; get first IP address byte
  709.     call    get_number
  710.     mov    byte ptr test_address, cl
  711.     lodsb
  712.     cmp    al, '.'
  713.     jne    no_more_args
  714.  
  715.     mov    di, offset temp_4bytes        ; get second IP address byte
  716.     call    get_number
  717.     mov    byte ptr test_address+1, cl
  718.     lodsb
  719.     cmp    al, '.'
  720.     jne    no_more_args
  721.  
  722.     mov    di, offset temp_4bytes        ; get third IP address byte
  723.     call    get_number
  724.     mov    byte ptr test_address+2, cl
  725.     lodsb
  726.     cmp    al, '.'
  727.     jne    no_more_args
  728.  
  729.     mov    di, offset temp_4bytes        ; get first IP address byte
  730.     call    get_number
  731.     mov    byte ptr test_address+3, cl
  732.  
  733. ;    mov    dx, offset test_arg_msg
  734. ;    mov    di, offset test_address
  735. ;push    si
  736. ;    call    print_ip_addr
  737. ;pop    si
  738.  
  739.     mov    ax, word ptr test_address
  740.     mov    word ptr static_address, ax
  741.     mov    ax, word ptr test_address+2
  742.     mov    word ptr static_address+2, ax
  743.     mov    use_static, 01H
  744.  
  745.     lodsb
  746.     cmp    al, ']'
  747.     je    arg_return
  748.  
  749. ;exit with nc if all went well, cy otherwise.
  750. no_more_args:
  751.     dec    si
  752. arg_return:
  753.     clc
  754.     ret
  755.  
  756.  
  757. ; Initialize our interface to the ATALK.SYS driver.
  758. ; NOTE: this initialization code is modeled after the PC/IP LocalTalk
  759. ; driver written by Dan Lanciani (ddl@harvard.harvard.edu); the PCIP
  760. ; software package can found at husc6.harvard.edu:pub/pcip/pcip.tar.Z
  761.     public    etopen
  762. etopen:
  763.     assume    ds:code
  764.  
  765. ; ATALK.SYS driver may be loaded at a software interrupt somewhere
  766. ; between 5CH and 70H. Locate ATALK.SYS driver by scanning for signature.
  767. isATLoaded:                    ; Look for ATALK.SYS driver
  768.     cld
  769.     call    ATGetInt            ; Load start of intr range
  770.     mov    dx, ax                ; Save start value in DX
  771. chkloop:
  772.     cmp    dx, 70H                ; Scanned all possible vectors?
  773.     jne    checkstring            ; No, check this vector
  774.     xor    ax, ax                ; Yes, driver not found
  775.     jmp    chksplit            ; Skip ahead to return
  776. checkstring:
  777.     mov    bx, dx                ; Load intr# for scan
  778.     shl    bx, 1                ; Multiply by 2 (for seg bytes)
  779.     shl    bx, 1                ; Multiply by 2 (for off bytes)
  780.     xor    ax, ax
  781.     mov    es, ax                ; Lowest page of memory
  782.     lds    si, es:[bx]            ; Load vector for scan intr#
  783.     mov    ax, ds                ; Load segment this scan intr#
  784.     or    ax, si                ; OR with off this scan intr#
  785.     jz    keepchecking            ; Keep checking if no bits
  786.     sub    si, 16                ; Signature is just before code
  787.     mov    di, offset driverstring        ; Load compare string
  788.     mov    cx, 9                ; Load length of compare string
  789.     push    cs
  790.     pop    es
  791.     repe    cmpsb                ; Compare ds:si to es:di
  792.     jne    keepchecking            ; Keep checking if not matched
  793.     call    ATGetInt            ; Matched, get INT# again
  794.     cmp    ax, dx                ; INT# already set properly?
  795.     jz    chksplit            ; Yes, use this INT#
  796.                         ; No, we found INT# by scanning
  797.     call    ATPatch                ; Modify code to match scan
  798.     call    ATGetInt            ; Retrieve final INT#
  799.     jmp    chksplit            ; Skip ahead to return
  800.  
  801. keepchecking:                    ; Havent found ATALK.SYS driver
  802.     inc    dx                ; Check next possible INT#
  803.     jmp    chkloop                ; Loop back to check next INT#
  804.  
  805. chksplit:                    ; Done with scan for ATALK.SYS
  806.     cmp    ax, 00H                ; ATALK.SYS driver found?
  807.     jne    atalk_sys_found            ; Yes, skip ahead to continue
  808.  
  809.     mov    dx, offset no_atalk_sys_msg    ; No, ATALK.SYS not loaded
  810.     jmp    error_wrt            ; Skip ahead to report error
  811.  
  812. atalk_sys_found:                ; ATALK.SYS driver found
  813.     push    cs                ; Used DS for another purpose
  814.     pop    ds                ; Reset DS to our data
  815.     mov    dtemp, dx            ; Report intr# of ATALK.SYS
  816.     mov    di, offset dtemp
  817.     mov    dx, offset atalk_sys_found_msg
  818.     call    print_number
  819.  
  820. ; We need to establish our Appletalk node
  821. get_our_info:                    ; Get info params from ATALK
  822.     mov    MyInfo.atd_command, AT_GETNETINFO
  823.     mov    MyInfo.atd_status, -1        ; As per PC LocalTalk spec. [jgn]
  824.     mov    MyInfo.atd_compfun.offs, 0    ; No completion routine [jgn]
  825.     mov    MyInfo.atd_compfun.segm, 0
  826.     mov    bx, offset MyInfo
  827.     call    doATint
  828.  
  829.     cmp    MyInfo.atd_status, 00H        ; Already initialized?
  830.     je    get_ddp_socket            ; Yes, skip ahead
  831.  
  832.     mov    MyInfo.atd_command, AT_INIT    ; No, initialize our node
  833.     mov    MyInfo.atd_compfun.offs, 0    ; No completion routine [jgn]
  834.     mov    MyInfo.atd_compfun.segm, 0
  835.     mov    bx, offset MyInfo
  836.     call    doATint
  837.  
  838. ; We need to establish our AppleTalk/DDP socket
  839. get_ddp_socket:                    ; Open a DDP socket
  840.     mov    DDPio.ddp_command, DDP_OPENSOCKET
  841.     mov    DDPio.ddp_compfun.offs, 0    ; No completion routine [jgn]
  842.     mov    DDPio.ddp_compfun.segm, 0
  843.     mov    DDPio.ddp_buffptr.offs, offset preview_upcall
  844.     mov    DDPio.ddp_buffptr.segm, cs
  845.     mov    DDPio.ddp_socket, 72        ; ask for experimental sock#
  846.     mov    DDPio.ddp_type, 22        ; ask for IP socket type
  847.     mov    bx, offset DDPio            ; ds:bx-> DDP param block
  848.     call    doATint                ; ask ATALK.SYS for a socket
  849.  
  850.     cmp    DDPio.ddp_status, 00H        ; error return from ATALK.SYS?
  851.     je    chk_ddp_socket            ; no, skip ahead to continue
  852.                         ; yes, no socket for us
  853.     mov    ax, DDPio.ddp_status
  854.     mov    dtemp, ax
  855.     mov    di, offset dtemp
  856.     mov    dx, offset ddp_failed_msg
  857.     call    print_number            ; report error and stat return
  858.     jmp    error_ret
  859.  
  860. ;**** do we really require socket 72?
  861. chk_ddp_socket:                    ; check the socket we opened
  862.     cmp    DDPio.ddp_socket, 72        ; did we get the one requested?
  863.     je    ddp_ready            ; yes, socket is as expected
  864.                         ; no, but must have socket 72
  865.     mov    DDPio.ddp_command, DDP_CLOSESOCKET
  866.     mov    bx, offset DDPio
  867.     call    doATint                ; close the assigned socket
  868.  
  869.     mov    dx, offset ddp_wrong_socket_msg    ; load error msg
  870.     jmp    error_wrt            ; skip ahead to display and ret
  871.  
  872. ddp_ready:                    ; DDP socket 72 is ready
  873.     mov    DDPio.ddp_command, DDP_WRITE    ; Use param block for WRITE now
  874.  
  875. ; AppleTalk node and DDP socket have been established
  876.     mov    ax, MyInfo.inf_network
  877.     mov    word ptr dtemp, ax
  878.     mov    al, MyInfo.inf_nodeid
  879.     mov    ah, DDPio.ddp_socket
  880.     mov    byte ptr dtemp+2, al
  881.     mov    byte ptr dtemp+3, ah
  882.     mov    di, offset dtemp
  883.     mov    dx, offset atalk_open_msg
  884.     call    print_at_addr            ; display AppleTalk node info
  885.     mov    ax, 00H
  886.     mov    dtemp+2, ax
  887.  
  888. ; We need an IP gateway node
  889. nbp_ipgateway:                    ; Locate our IP gateway node
  890.     push    cs
  891.     pop    ds
  892.     mov    NBP.nbp_command, NBP_LOOKUP
  893.     mov    NBP.nbp_compfun.offs, 0        ; No completion routine [jgn]
  894.     mov    NBP.nbp_compfun.segm, 0
  895.     mov    NBP.nbp_toget, 01H
  896.     mov    NBP.nbp_buffptr.offs, offset NBPt
  897.     mov    NBP.nbp_buffptr.segm, ds
  898.     mov    NBP.nbp_buffsize, (size NBPTuple)
  899.     mov    NBP.nbp_interval, 5
  900.     mov    NBP.nbp_retry, 12
  901.     mov    NBP.nbp_entptr.offs, offset ipgateway_name
  902.     mov    NBP.nbp_entptr.segm, ds
  903.     mov    bx, offset NBP
  904.     call    doATint                ; do name-bind lookup
  905.  
  906.     cmp    NBP.nbp_status, 00H        ; status return=error?
  907.     jne    nbp_no_gateway            ; yes, report error and exit
  908.  
  909.     cmp    NBP.nbp_toget, 01H
  910.     je    atp_setup
  911.  
  912. nbp_no_gateway:                    ; NBP lookup failed
  913.     mov    ax, NBP.nbp_status
  914.     mov    dtemp, ax
  915.     mov    di, offset dtemp
  916.     mov    dx, offset nbp_no_gateway_msg    ; display error msg
  917.     call    print_number
  918.  
  919.     mov    DDPio.ddp_command, DDP_CLOSESOCKET
  920.     mov    bx, offset DDPio
  921.     call    doATint                ; close the assigned socket
  922.  
  923.     jmp    error_ret            ; skip ahead to return
  924.  
  925. ; We need a transport layer to the IP gateway
  926. atp_setup:
  927.     mov    cx, (size AddrBlk)        ; MyGateway = NBPt.tup_addr
  928.     push    cs
  929.     pop    es
  930.     mov    si, offset NBPt.tup_address
  931.     mov    di, offset MyGateway
  932.     rep    movsb
  933.  
  934.     mov    di, offset NBPt.tup_address    ; Display our gateway node
  935.     mov    dx, offset nbp_ipg_addr_msg
  936.     call    print_at_addr
  937.  
  938.     cmp    use_static, 00H            ; Do we have a static address? [jgn]
  939.     je    bds_setup            ; No, don't change anything
  940.     mov    IPG.ipg_opcode+3, 3        ; Yes, change to IPG_SERVER
  941.  
  942. bds_setup:
  943.     mov    BDS.bds_buffptr.offs, offset IPG
  944.     mov    BDS.bds_buffptr.segm, ds
  945.     mov    BDS.bds_buffsize, (size IPGInfo)
  946.  
  947.     mov    ATP.atp_command, ATP_SEND_REQUEST
  948.     mov    ATP.atp_compfun.offs, 0        ; No completion routine [jgn]
  949.     mov    ATP.atp_compfun.segm, 0
  950.     mov    cx, (size AddrBlk)        ; ATP.atp_addr = NBPt.tup_addr
  951.     push    cs
  952.     pop    es
  953.     mov    si, offset NBPt.tup_address
  954.     mov    di, offset ATP.atp_addrblk
  955.     rep    movsb
  956.     mov    ATP.atp_buffptr.offs, offset IPG
  957.     mov    ATP.atp_buffptr.segm, ds
  958.     mov    ATP.atp_buffsize, (size IPGInfo)
  959.     mov    ATP.atp_interval, 05H
  960.     mov    ATP.atp_retry, 05H
  961.     mov    ATP.atp_flags, XO_BIT
  962.     mov    ATP.atp_bdsbuffs, 01H
  963.     mov    ATP.atp_bdsptr.offs, offset BDS
  964.     mov    ATP.atp_bdsptr.segm, ds
  965.     mov    bx, offset ATP
  966.     call    doATint
  967.  
  968.     cmp    ATP.atp_status, 00H        ; status return=error?
  969.     jne    atp_no_gateway            ; yes, report error and exit
  970.  
  971.     cmp    ATP.atp_bdsbuffs, 01H
  972.     je    chk_ip_opcode
  973.  
  974. atp_no_gateway:                    ; ATP setup failed
  975.     mov    ax, ATP.atp_status
  976.     mov    dtemp, ax
  977.     mov    di, offset dtemp
  978.     mov    dx, offset atp_no_gateway_msg    ; display error msg
  979.     call    print_number
  980.  
  981.     mov    DDPio.ddp_command, DDP_CLOSESOCKET
  982.     mov    bx, offset DDPio
  983.     call    doATint                ; close the assigned socket
  984.  
  985.     jmp    error_ret            ; skip ahead to return
  986.  
  987. chk_ip_opcode:
  988.     cmp    IPG.ipg_opcode.offs, IPG_ERROR    ; opcode is 32 bit
  989.     jne    save_ipaddr            ; check one word at a time
  990.     cmp    IPG.ipg_opcode.segm, IPG_ERROR    ; error from IP gateway?
  991.     jne    save_ipaddr            ; no, transport established
  992.                         ; yes, ATP setup failed
  993.     mov    dx, offset ipg_gateway_err_msg    ; display IPG error msg
  994.     mov    ah, 9
  995.     int    21H
  996.     mov    dx, offset IPG.ipg_string
  997.     mov    ah, 9
  998.     int    21H
  999.     mov    al, 13                ; display CR-LF
  1000.     call    chrout
  1001.     mov    al, 10
  1002.     call    chrout
  1003.  
  1004.     mov    DDPio.ddp_command, DDP_CLOSESOCKET
  1005.     mov    bx, offset DDPio
  1006.     call    doATint                ; close the assigned socket
  1007.  
  1008.     jmp    error_ret
  1009.  
  1010. ; AppleTalk/IP transport layer established
  1011. save_ipaddr:
  1012.     mov    dx, offset myip_addr_msg
  1013.     cmp    use_static, 00H
  1014.     jne    show_static
  1015. show_dynamic:
  1016.     mov    di, offset IPG.ipg_ipaddress
  1017.     jmp    show_ipaddr
  1018. show_static:
  1019.     mov    di, offset static_address
  1020. show_ipaddr:
  1021.     call    print_ip_addr
  1022.  
  1023.     mov    dx, offset ns_ip_addr_msg
  1024.     mov    di, offset IPG.ipg_ipname
  1025.     call    print_ip_addr
  1026.  
  1027.     mov    dx, offset bd_ip_addr_msg
  1028.     mov    di, offset IPG.ipg_ipbroad
  1029.     call    print_ip_addr
  1030.  
  1031.     mov    dx, offset fs_ip_addr_msg
  1032.     mov    di, offset IPG.ipg_ipfile
  1033.     call    print_ip_addr
  1034.  
  1035. ; We need to register ourself with the AppleTalk Name Binding Agent
  1036. nbp_register_ourself:
  1037.     mov    al, MyInfo.inf_nodeid
  1038.     mov    NBPtable.tab_entry.tup_address.ablk_nodeid, al
  1039.     mov    al, DDPio.ddp_socket
  1040.     mov    NBPtable.tab_entry.tup_address.ablk_socket, al
  1041.  
  1042.     ; print our IP address in our NBP table entry
  1043.     mov    bx, offset NBPtable.tab_entry.tup_name
  1044.     inc    bx
  1045.     xor    dx, dx
  1046.     cmp    use_static, 00H
  1047.     jne    reg_static1
  1048. reg_dynamic1:
  1049.     mov    dl, byte ptr IPG.ipg_ipaddress
  1050.     jmp    reg_format1
  1051. reg_static1:
  1052.     mov    dl, byte ptr static_address
  1053. reg_format1:
  1054.     call    decstr
  1055.     mov    al, dot_char
  1056.     mov    byte ptr ds:[bx], al
  1057.     inc    bx
  1058.     cmp    use_static, 00H
  1059.     jne    reg_static2
  1060. reg_dynamic2:
  1061.     mov    dl, byte ptr IPG.ipg_ipaddress+1
  1062.     jmp    reg_format2
  1063. reg_static2:
  1064.     mov    dl, byte ptr static_address+1
  1065. reg_format2:
  1066.     call    decstr
  1067.     mov    al, dot_char
  1068.     mov    ds:[bx], al
  1069.     inc    bx
  1070.     cmp    use_static, 00H
  1071.     jne    reg_static3
  1072. reg_dynamic3:
  1073.     mov    dl, byte ptr IPG.ipg_ipaddress+2
  1074.     jmp    reg_format3
  1075. reg_static3:
  1076.     mov    dl, byte ptr static_address+2
  1077. reg_format3:
  1078.     call    decstr
  1079.     mov    al, dot_char
  1080.     mov    ds:[bx], al
  1081.     inc    bx
  1082.     cmp    use_static, 00H
  1083.     jne    reg_static4
  1084. reg_dynamic4:
  1085.     mov    dl, byte ptr IPG.ipg_ipaddress+3
  1086.     jmp    reg_format4
  1087. reg_static4:
  1088.     mov    dl, byte ptr static_address+3
  1089. reg_format4:
  1090.     call    decstr
  1091.  
  1092.     mov    ax, bx
  1093.     sub    ax, offset NBPtable.tab_entry.tup_name
  1094.     sub    ax, 1
  1095.     mov    NBPtable.tab_entry.tup_name, al
  1096.  
  1097.     mov    cx, myip_name_len    ; append IPADDR command to our IP
  1098.     push    cs
  1099.     pop    es
  1100.     mov    si, offset myip_name    ; ds:si -> source
  1101.     mov    di, bx            ; es:di -> dest
  1102.     rep    movsb
  1103.  
  1104.     ; Register our name with NBP agent
  1105.     mov    NBP.nbp_command, NBP_REGISTER
  1106.     mov    NBP.nbp_compfun.offs, 0        ; No completion routine [jgn]
  1107.     mov    NBP.nbp_compfun.segm, 0
  1108.     mov    NBP.nbp_buffptr.offs, offset NBPtable
  1109.     mov    NBP.nbp_buffptr.segm, ds
  1110.     mov    NBP.nbp_interval, 01H
  1111.     mov    NBP.nbp_retry, 03H
  1112.     mov    bx, offset NBP
  1113.     call    doATint
  1114.  
  1115.     cmp    NBP.nbp_status, 00H
  1116.     je    atinit_done
  1117.  
  1118. nbp_no_register:
  1119.     mov    ax, NBP.nbp_status
  1120.     mov    dtemp, ax
  1121.     mov    di, offset dtemp
  1122.     mov    dx, offset nbp_no_register_msg    ; display error msg
  1123.     call    print_number
  1124.  
  1125.     mov    DDPio.ddp_command, DDP_CLOSESOCKET
  1126.     mov    bx, offset DDPio
  1127.     call    doATint                ; close the assigned socket
  1128.  
  1129.     jmp    error_ret            ; skip ahead to return
  1130.  
  1131. ;**** LocalTalk PC Card initialized, ready to TSR
  1132. atinit_done:
  1133.     push    cs
  1134.     pop    ds
  1135.     mov    dx, offset end_resident
  1136.     clc
  1137.     ret
  1138.  
  1139. ;**** Got an error while initializing LocalTalk PC Card
  1140. error_wrt:                    ; Display an error message
  1141.     push    cs                ; Get our data segment back
  1142.     pop    ds
  1143.     mov    ah, 9
  1144.     int    21H
  1145.  
  1146. error_ret:                    ; Board not initialized
  1147.     stc
  1148.     ret
  1149.  
  1150.     public    print_parameters
  1151. print_parameters:
  1152. ;echo our command-line parameters
  1153.     ret
  1154.  
  1155. ;*******************************************
  1156.  
  1157. ; Modify ATALK.SYS interrupt number in doATint code (self-modifying code!)
  1158. ATPatch:
  1159.     mov    al, dl                ; Load new interrupt number
  1160.     push    cs
  1161.     pop    es
  1162.     lea    bx, doATint            ; es:bx=offset of doATint code
  1163.     inc    bx                ; skip to operator for INT
  1164.     mov    es:[bx], al            ; modify the code
  1165.     ret
  1166.  
  1167. ; Get ATALK.SYS interrupt number
  1168. ATGetInt:
  1169.     push    cs
  1170.     pop    es
  1171.     lea    bx, doATint            ; es:bx=offset of doATint code
  1172.     inc    bx                ; skip to operator for INT
  1173.     mov    al, es:[bx]            ; load operator for INT
  1174.     xor    ah, ah                ; zero high byte
  1175.     ret                    ; return INT# to caller
  1176.  
  1177. ;*******************************************
  1178.  
  1179. ;*******************************************
  1180.  
  1181. ; caller must set ds:si -> dest for string, dx 16-bit value to sprint
  1182. decstr:
  1183.     mov    di,dx
  1184.     cmp    dx, 0
  1185.     jne    decstr_nonzero
  1186.     mov    al,'0'            ;yes - easier to just print it, than
  1187.     jmp    chrstr            ;  to eliminate all but the last zero.
  1188. decstr_nonzero:
  1189.  
  1190.     xor    ax,ax            ;start with all zeroes in al,bx,bp
  1191.     mov    bp,ax
  1192.  
  1193.     mov    cx,16            ;16 bits in one 16 bit registers.
  1194. decstr_1:
  1195.     rcl    di,1
  1196.     xchg    bp,ax
  1197.     call    addbit
  1198.     xchg    bp,ax
  1199.     adc    al,al
  1200.     daa
  1201.     loop    decstr_1
  1202.  
  1203.     mov    cl,'0'            ;prepare to eliminate leading zeroes.
  1204.     call    bytestr            ;output the first two.
  1205.     mov    ax,bp
  1206.     jmp    wordstr            ;output the next four.
  1207.  
  1208. addbit:    adc    al,al
  1209.     daa
  1210.     xchg    al,ah
  1211.     adc    al,al
  1212.     daa
  1213.     xchg    al,ah
  1214.     ret
  1215.  
  1216. ;print the char in al at ds:bx
  1217. chrstr:
  1218.     mov    byte ptr [bx], al
  1219.     inc    bx
  1220.     ret
  1221.  
  1222. wordstr:
  1223.     push    ax
  1224.     mov    al,ah
  1225.     call    bytestr
  1226.     pop    ax
  1227. bytestr:
  1228.     mov    ah,al
  1229.     shr    al,1
  1230.     shr    al,1
  1231.     shr    al,1
  1232.     shr    al,1
  1233.     call    digstr
  1234.     mov    al,ah
  1235. digstr:
  1236.     and    al,0fh
  1237.     add    al,90h    ;binary digit to ascii hex digit.
  1238.     daa
  1239.     adc    al,40h
  1240.     daa
  1241.     cmp    al,cl            ;leading zero?
  1242.     je    digstr_1
  1243.     mov    cl,-1            ;no more leading zeros.
  1244.     jmp    chrstr
  1245. digstr_1:
  1246.     ret
  1247.  
  1248. ; caller must set ds:dx -> argument string, ds:di -> AddrBlk struct
  1249. print_at_addr:
  1250. ;enter with dx -> dollar terminated name of number, di ->dword.
  1251. ;exit with the number printed and the cursor advanced to the next line.
  1252.     mov    ah,9            ;print the name of the number.
  1253.     int    21h
  1254.     mov    ax, [di].ablk_network    ;print the network number
  1255.     xchg    ah, al            ; byte-swap network number [jgn]
  1256.     mov    dx, 00H
  1257.     push    di
  1258.     call    decout
  1259.     pop    di
  1260.     mov    al, ':'
  1261.     call    chrout
  1262.     xor    ax, ax
  1263.     mov    al, [di].ablk_nodeid    ; print the nodeid number
  1264.     push    di
  1265.     call    decout
  1266.     pop    di
  1267.     mov    al, ':'
  1268.     call    chrout
  1269.     xor    ax, ax
  1270.     mov    al, [di].ablk_socket    ; print the socket number
  1271.     call    decout
  1272.     mov    al,CR
  1273.     call    chrout
  1274.     mov    al,LF
  1275.     call    chrout
  1276.     ret
  1277.  
  1278. ; caller must set ds:dx -> argument string, ds:di -> 32 bit ip address
  1279. print_ip_addr:
  1280. ;enter with dx -> dollar terminated name of number, di ->dword.
  1281. ;exit with the number printed and the cursor advanced to the next line.
  1282.     mov    ah,9            ;print the name of the number.
  1283.     int    21h
  1284.     mov    al, '['
  1285.     call    chrout
  1286.     xor    ax, ax
  1287.     mov    al, [di]        ;print first byte in decimal.
  1288.     mov    dx, 00H
  1289.     push    di
  1290.     call    decout
  1291.     pop    di
  1292.     mov    al, '.'
  1293.     call    chrout
  1294.     xor    ax, ax
  1295.     mov    al, [di+1]        ; print second byte in decimal
  1296.     push    di
  1297.     call    decout
  1298.     pop    di
  1299.     mov    al, '.'
  1300.     call    chrout
  1301.     xor    ax, ax
  1302.     mov    al, [di+2]        ; print third byte in decimal
  1303.     push    di
  1304.     call    decout
  1305.     pop    di
  1306.     mov    al, '.'
  1307.     call    chrout
  1308.     xor    ax, ax
  1309.     mov    al, [di+3]        ; print fourth byte in decimal
  1310.     call    decout
  1311.     mov    al, ']'
  1312.     call    chrout
  1313.     mov    al,CR
  1314.     call    chrout
  1315.     mov    al,LF
  1316.     call    chrout
  1317.     ret
  1318.  
  1319. code    ends
  1320.  
  1321.     end
  1322.  
  1323.